package org.jside.xtools.watermark;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class WaterMarker extends JFrame {
	//
	// "if(location.protocol!='file:')document.write('<style>.bd-w-{display:none;}</style>')".replace(/./g,function(c){return
	// c.charCodeAt()+','})

	private final String unwalterScript = "<script>eval('105,102,40,108,111,99,97,116,105,111,110,46,112,114,111,116,111,99,111,108,33,61,39,102,105,108,101,58,39,41,100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,115,116,121,108,101,62,46,98,100,45,119,45,123,100,105,115,112,108,97,121,58,110,111,110,101,59,125,60,47,115,116,121,108,101,62,39,41,'.replace(/(\\d+),/g,function(w,c){return String.fromCharCode(c)}))</script>";
	private final String rewalterScript = "<script>eval('105,102,40,108,111,99,97,116,105,111,110,46,112,114,111,116,111,99,111,108,61,61,39,102,105,108,101,58,39,41,100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,115,116,121,108,101,62,46,98,100,45,119,45,123,100,105,115,112,108,97,121,58,105,110,108,105,110,101,59,125,60,47,115,116,121,108,101,62,39,41,'.replace(/(\\d+),/g,function(w,c){return String.fromCharCode(c)}))</script>";
	// private final String encoding = "utf-8";// "GBK";// "ISO-8895"

	private JFileChooser fileChooser = new JFileChooser();
	{
		fileChooser.setDialogTitle("选择网站目录");
		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
			@Override
			public boolean accept(File f) {
				return f.isDirectory();
			}

			@Override
			public String getDescription() {
				return "选择网站目录";
			}

		});
	}

	private JTextField sourceInput = new JTextField();
			//"C:\\Documents and Settings\\Administrator\\桌面\\JSISide\\JSISide\\web\\decorator");
	private JButton sourceButton = new JButton("选择源文件目录");
	private JTextField destInput = new JTextField();
			//"C:\\Documents and Settings\\Administrator\\桌面\\JSISide\\JSISide\\web\\decorator2");
	private JButton destButton = new JButton("选择源文件目录");
	private JButton beginButton = new JButton("开始打水印");
	private JTextArea output = new JTextArea();

	private LinkedHashMap<String, JRadioButton> encodingMap = new LinkedHashMap<String, JRadioButton>();
	{
		encodingMap.put("UTF-8", new JRadioButton("UTF-8"));
		encodingMap.put("GBK", new JRadioButton("GBK", true));
	}

	public WaterMarker() {
		initialize();
		for (final JRadioButton btn : encodingMap.values()) {
			btn.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					boolean selected = btn.isSelected();
					for (JRadioButton btn2 : encodingMap.values()) {
						if (btn2 != btn) {
							btn2.setSelected(!selected);
						}
					}
				}

			});
		}
		sourceButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileChooser.setSelectedFile(new File(sourceInput.getText()));
				int status = fileChooser.showOpenDialog(WaterMarker.this);
				if (status == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					try {
						sourceInput.setText(file.getCanonicalPath());
					} catch (IOException e1) {
						output.append("ERROR:" + e1.getMessage());
					}
				}
			}
		});
		destButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileChooser.setSelectedFile(new File(destInput.getText()));
				int status = fileChooser.showOpenDialog(WaterMarker.this);
				if (status == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					try {
						destInput.setText(file.getCanonicalPath());
					} catch (IOException e1) {
						output.append("ERROR:" + e1.getMessage());
					}
				}
			}
		});
		beginButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				File sourceFile = new File(sourceInput.getText());
				String dest = destInput.getText();
				if (sourceFile.exists() && dest.length() > 0) {
					File destFile = new File(dest);
					if (destFile.exists()) {
						int status = JOptionPane.showConfirmDialog(
								WaterMarker.this, "目标目录已经存在:"+destFile+"\r\b继续操作将覆盖目标目录");
						if (status != JOptionPane.OK_OPTION) {
							return;
						}
					}
					walk(sourceFile, destFile);

				}else{
					JOptionPane.showConfirmDialog(
							WaterMarker.this, "请选择源文件目录和目标文件目录");
				}
			}
		});
	}

	private String getEncodingMap() {
		for (String encoding : encodingMap.keySet()) {
			if (encodingMap.get(encoding).isSelected()) {
				return encoding;
			}
		}
		return "utf-8";
	}

	public void info(String msg) {
		this.output.append(msg + "\r\n");
	}

	private void initialize() {
		this.setTitle("网站水印工具");
		this.setSize(new Dimension(600, 500));
		this.setPreferredSize(new Dimension(600, 500));

		GridBagLayout layout = new GridBagLayout();
		this.setLayout(layout);

		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.BOTH;
		c.insets = new Insets(4, 4, 4, 4);

		c.weightx = 6.0;
		c.gridwidth = 1;
		this.add(sourceInput, c);

		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(sourceButton, c);

		c.weightx = 6.0;
		c.gridwidth = 1;
		this.add(destInput, c);

		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(destButton, c);

		c.weightx = 1.0;
		c.gridwidth = 1;
		JPanel encodingPanel = new JPanel();
		encodingPanel.add(new JLabel("选择文件编码："));
		for (JRadioButton btn : encodingMap.values()) {
			encodingPanel.add(btn);
		}
		this.add(encodingPanel, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(beginButton, c);

		c.weightx = 1.0;
		c.fill = GridBagConstraints.BOTH;
		c.weighty = 100;
		c.anchor = GridBagConstraints.CENTER;
		c.gridwidth = GridBagConstraints.REMAINDER;
		output.setBorder(BorderFactory.createEtchedBorder());
		this.add(new JScrollPane(output), c);

		c.fill = GridBagConstraints.NONE;
		c.weighty = 1;
		c.anchor = GridBagConstraints.CENTER;
		c.gridwidth = GridBagConstraints.REMAINDER;

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		WaterMarker marker = new WaterMarker();
		marker.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		marker.setVisible(true);
	}

	private Collection<String> waterExtMap = new HashSet<String>(Arrays
			.asList("html,htm".split("[,]")));

	protected void walk(final File source, final File dest) {
		if (!dest.exists()) {
			dest.mkdirs();
		}
		File[] dirs = source.listFiles(new java.io.FileFilter() {
			public boolean accept(File file) {
				if (file.isDirectory()) {
					walk(file, new File(dest, file.getName()));
				} else {
					try {
						String name = file.getName();
						String ext = name.substring(name.lastIndexOf('.') + 1)
								.toLowerCase();
						if (waterExtMap.contains(ext)) {
							transform(file, new File(dest, name));
						} else {
							copy(file, new File(dest, name));
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				return false;
			}
		});
	}

	protected void copy(File source, File dest) throws IOException {
		dest.createNewFile();
		FileInputStream in = new FileInputStream(source);
		FileOutputStream out = new FileOutputStream(dest);

		byte[] cbuf = new byte[1024];
		int count;
		while ((count = in.read(cbuf)) >= 0) {
			out.write(cbuf, 0, count);
		}
		out.flush();
		out.close();
	}

	protected void transform(File source, File dest) throws IOException {
		dest.createNewFile();
		Reader in = new InputStreamReader(new FileInputStream(source),
				getEncodingMap());
		Writer out = new OutputStreamWriter(new FileOutputStream(dest),
				getEncodingMap());

		StringWriter temp = new StringWriter();
		char[] cbuf = new char[1024];
		int count;
		while ((count = in.read(cbuf)) >= 0) {
			temp.write(cbuf, 0, count);
		}
		String data = temp.toString();

		Pattern splitPattern = Pattern
				.compile(
						"<textarea[\\s\\S]*?</textarea>|<script[\\s\\S]*?</script>|<style[\\s\\S]*?</style>|<[^>]+>|&#?[\\w]{1,8};|[\\s\\S]+?",
						Pattern.CASE_INSENSITIVE);
		// Pattern testPattern =
		// Pattern.compile("</textarea>|</script>",Pattern.CASE_INSENSITIVE);
		Matcher matchs = splitPattern.matcher(data);
		int state = 0;
		int inPre = 0;// <pre>
		boolean needUnwalterScript = true;
		boolean needRewalterScript = true;
		while (matchs.find()) {
			String text = matchs.group();
			if (text.length() > 0) {
				if (text.charAt(0) == '<') {
					if (text.length() >= 5) {
						String flag = text.substring(0, 5);

						if (flag.equalsIgnoreCase("<body")) {
							if (needUnwalterScript) {
								out.write(unwalterScript);
								needUnwalterScript = false;
							}
							state = 2;
						}
						if (!needUnwalterScript && needRewalterScript
								&& Math.random() > 0.8) {
							out.write(rewalterScript);
							needRewalterScript = false;
						}

						if (flag.substring(0, 4).equalsIgnoreCase("<pre")) {
							inPre++;
						}
						if (text.equalsIgnoreCase("</pre")) {
							inPre--;
						}

						if (flag.equalsIgnoreCase("</bod")) {
							if (needUnwalterScript) {
								out.write(unwalterScript);
								needUnwalterScript = false;
							}

							if (needRewalterScript) {
								out.write(rewalterScript);
								needRewalterScript = false;
							}
						}
					}
				} else {
					// 处理文本节点
					if (inPre == 0) {
						text = text.trim();
					}
					// 处理文本节点
					if (state == 2 && text.trim().length() > 0) {
						text = mark(text);
					}
				}
			}
			out.write(text);
		}
		info("INFO:文件" + dest + "转换成功");
		out.flush();
		out.close();

	}

	protected String mark(String text) {
		if (text.startsWith("&")) {
			return text;
		} else {
			StringBuffer buf = new StringBuffer(text);
			String mark = "<span class='bd-w-'>%</span>";
			int position = (int) (text.length() * Math.random());
			while (true) {
				int start = position > 2 ? position - 2 : 0;
				int end = Math.min(start + 3, text.length());
				buf.insert(position, mark.replace("%", text.substring(start,
						end)));
				int position2 = (int) (text.length() * Math.random());
				if (position2 < position) {
					position = position2;
				} else {
					break;
				}
			}
			return buf.toString();
		}
	}

}
